package com.fufan.mtsaas.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.plugins.Page;
import com.fufan.mtsaas.cache.Cache;
import com.fufan.mtsaas.constant.RedisKeyConstant;
import com.fufan.mtsaas.modules.base.intflog.dao.TIntfLogDao;
import com.fufan.mtsaas.modules.base.intflog.model.TIntfLog;
import com.fufan.mtsaas.modules.common.bo.response.RequestPojo;
import com.fufan.mtsaas.modules.common.bo.response.ResStatus;
import com.fufan.mtsaas.modules.common.bo.response.Result;
import com.fufan.mtsaas.modules.sysmgr.journal.model.AiIntrmgrProcess;
import com.fufan.mtsaas.modules.sysmgr.sygroup.bo.response.SYGroupMenuInfo;
import com.fufan.mtsaas.modules.sysmgr.sygroup.dao.SYgroupMenuDao;
import com.fufan.mtsaas.modules.sysmgr.syuser.dao.SYuserDao;
import com.fufan.mtsaas.modules.sysmgr.syuser.model.SYuser;
import com.fufan.mtsaas.modules.base.company.dao.TCompanyPurchaseDao;
import com.fufan.mtsaas.tools.AESTool;
import com.fufan.mtsaas.util.ParamUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 请求过滤器
 *
 * @version 1.0
 * @auther Liby
 * @create 2018/4/17
 **/
@Component
@WebFilter
@Slf4j
public class RequestFilter implements Filter {

//    @Autowired
//    private AiIntrmgrProcessDao aiIntrmgrProcessDao;
//    @Autowired
//    private AiStuffLogDao aiStuffLogDao;

    /**
     * 白名单
     */
    private static final List<String> paths = Arrays.asList("/fileupload/imgUpload","/SYS/HRAILOGIN/LOGIN", "/ERROR/session","/swagger-ui.html"
            ,"/doc/type/outPutLocal3","/doc/type/outPutLocal2","/offline/resource","/webjars/css/app.3167b4c3.css"
            ,"/webjars/js/app.e4826b43.js","/webjars/js/chunk-vendors.86544bae.js","/v2","/swagger-resources","/doc.html"
            , "SYS/SMS", "swagger", "LOGIN", "api-docs", "/favicon.ico", "/swagger-resources/configuration/ui", "/api-docs", "/home/getCaptcha");
    @Autowired
    private ParamUtil paramUtil;
    @Autowired
    private SYgroupMenuDao sYgroupMenuDao;
    @Autowired
    private SYuserDao sYuserDao;
    @Autowired
    private TIntfLogDao tIntfLogDao;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private TCompanyPurchaseDao tCompanyPurchaseDao;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        //每次异步请求都发起预检请求
        httpServletResponse.setHeader("Access-Control-Max-Age", "0");
        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
//        ContentCachingRequestWrapper contentCachingRequestWrapper = null;
//        try {
//            contentCachingRequestWrapper =  new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);
//        }catch (Exception e){
//
//        }
        /**
         * 设置跨域访问
         */


        String method = httpServletRequest.getMethod();
        if ("OPTIONS".equals(method)) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            //  filterChain.doFilter(contentCachingRequestWrapper, servletResponse);
            return;
        }
        String uri  = ((HttpServletRequest) servletRequest).getRequestURI();

        servletResponse.setCharacterEncoding("UTF-8");
        servletResponse.setContentType("application/json;charset=UTF-8");
        //校验token
        PrintWriter out = null;

        if (isInclude(uri) && !uri.equals("/")) {
            try {
                boolean access = paramUtil.verifyToken();
                if(!access){
                    out = servletResponse.getWriter();
                    Result result = new Result<>();
                    result.setResStatus(ResStatus.STATUS_REG_NO_TOKEN);
                    result.setResMsg(ResStatus.STATUS_REG_NO_TOKEN_MSG);
                    out.write(JSONObject.toJSONString(result));
                    return ;
                }else {
                    RequestPojo requestPojo = ParamUtil.doChange();
                    Map<String,String> userMap = new HashMap<>();
                    String userRedisId = stringRedisTemplate.opsForValue().get(RedisKeyConstant.USER_MODIFY_LOCK + ":" +requestPojo.getStaffId());
                    Result result = new Result<>();
                    if(StringUtils.isEmpty(userRedisId)){
                        out = servletResponse.getWriter();
                        result.setResStatus(ResStatus.STATUS_USER_IS_EMPTY);
                        result.setResMsg(ResStatus.STATUS_USER_IS_EMPTY_MSG);
                        out.write(JSONObject.toJSONString(result));
                        return ;
                    }
                    userMap.put("id",userRedisId);
                    List<SYuser> sYuserList = sYuserDao.selectList(new Page<>(), userMap);
                    if (CollectionUtils.isNotEmpty(sYuserList) && sYuserList.size() > 0 && (Objects.isNull(sYuserList.get(0).getVldFG()) || sYuserList.get(0).getVldFG().equals("1"))) {
                        out = servletResponse.getWriter();
                        result.setResStatus(ResStatus.STATUS_ORDER_IS_STOP);
                        result.setResMsg(ResStatus.STATUS_ORDER_IS_STOP_MSG);
                        out.write(JSONObject.toJSONString(result));
                        return ;
                    }
                }

            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }

        //验证权限
        RequestPojo requestPojo = ParamUtil.doChange();
        if (requestPojo != null) {
            try {
                boolean auth = false;
                if (Cache.ROLE_URL_MAP.containsKey(((HttpServletRequest) servletRequest).getRequestURI())) {
                    Map<String, String> mapData = new HashMap<>();
                    String userRedisId = stringRedisTemplate.opsForValue().get(RedisKeyConstant.USER_MODIFY_LOCK + ":" +requestPojo.getStaffId());
                    Map<String,String> userMap = new HashMap<>();
                    userMap.put("id",userRedisId);
                    List<SYuser> sYuserList = sYuserDao.selectList(new Page<>(), userMap);
                    if(sYuserList != null && sYuserList.size() > 0 && StringUtils.isNotEmpty(userRedisId)){
                        mapData.put("GroupID", sYuserList.get(0).getUserGroupID());
                        List<SYGroupMenuInfo> sYgroupMenuList = sYgroupMenuDao.selectList(new Page<>(), mapData);
                        for (String aa : Cache.ROLE_URL_MAP.get(((HttpServletRequest) servletRequest).getRequestURI()).split(";")) {
                            if (sYgroupMenuList.get(0).getRW().contains(aa)) {
                                auth = true;
                                break;
                            }
                        }
                        if (!auth) {
                            try {
                                out = servletResponse.getWriter();
                                Result result = new Result<>();
                                result.setResStatus(ResStatus.STATUS_ROLE_NOT_ACCESS);
                                result.setResMsg(ResStatus.STATUS_ROLE_NOT_ACCESS_MSG);
                                out.write(JSONObject.toJSONString(result));
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                            return;
                        }
                    }
                }
            }catch (Exception e){

            }
        }
        //打印日志

//        try {
//
//            String body = IOUtils.toString(contentCachingRequestWrapper.getBody(),servletRequest.getCharacterEncoding());
//            JSONObject obj = JSON.parseObject(body);
//            log.info("请求地址" + ((HttpServletRequest) servletRequest).getRequestURI() + "请求内容：" + obj);
//        }catch (Exception e){
//
//        }


        /**
         * 访问白名单
         */
        if (!isInclude(uri)) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }
        String url = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length());
        log.debug("url: {}, method: {}", url, method);

        if (url.startsWith("/") && url.length() > 1) {
            url = url.substring(1);
        }

        if ("MTSaas".equals(url.split("/")[0])) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

        if ("SYS".equals(url.split("/")[0])) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

        if ("UDI".equals(url.split("/")[0])) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }

//        if ("API".equals(url.split("/")[0])) {
//            StringBuffer sb = new StringBuffer();
//            InputStream is = httpServletRequest.getInputStream();
//            BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
//            String str = "";
//            while ((str = br.readLine()) != null) {
//                sb.append(str);
//            }
//            JSONObject jsonObject = JSONObject.parseObject(sb.toString());
//            JSONObject jmetdata = jsonObject.getJSONObject("metdata");
//            MDC.put("staff", jmetdata.getString("user"));
//            MDC.put("code", jmetdata.getString("model_code"));
//            AiIntrmgrProcess aiIntrmgrProcess = new AiIntrmgrProcess();
//            aiIntrmgrProcess.setFuncCode(url);
//            aiIntrmgrProcess.setIntfId(UUID.randomUUID().toString());
//            aiIntrmgrProcess.setIntfReqMessage(jsonObject.toString());
//            aiIntrmgrProcess.setIntfVersion("1.0");
//            aiIntrmgrProcess.setSysReqsrc(jmetdata.getString("req_src"));
//            aiIntrmgrProcess.setSysOper(jmetdata.getString("user"));
//            aiIntrmgrProcess.setSysIp(jmetdata.getString("ip_address"));
//            aiIntrmgrProcess.setSysStart(new Date(System.currentTimeMillis()));
//            aiIntrmgrProcess.setFromSysReqsrc("API");
//            aiIntrmgrProcess.setToSysReqsrc("AISERVICE");
//            try {
////                aiIntrmgrProcessDao.insert(aiIntrmgrProcess);
//            } catch (Exception e) {
//                log.error("插入AI处理日志表信息出错！" + aiIntrmgrProcess.toString());
//                log.error("插入AI处理日志表信息出错！", e);
//            }
//            HttpSession session = httpServletRequest.getSession();
//            session.setAttribute(session.getId() + "aiIntrmgrProcess", aiIntrmgrProcess.getIntfId());
//            ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper(httpServletRequest);
//            requestWrapper.addParameter("data", jsonObject);
//            filterChain.doFilter(requestWrapper, httpServletResponse);
////            filterChain.doFilter(contentCachingRequestWrapper, servletResponse);
//            return;
//        }
        /**
         * 获取传入参数
         * 解密
         */
        String reqData = "";

        if ("POST".equals(method) || "PUT".equals(method) || "PATCH".equals(method) || "DELETE".equals(method)) {
            StringBuffer sb = new StringBuffer();
            InputStream is = httpServletRequest.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
            String str = "";
            while ((str = br.readLine()) != null) {
                sb.append(str);
            }
            JSONObject jsonObject = null;
            jsonObject = JSONObject.parseObject(sb.toString());
            reqData = jsonObject.getString("data");
        } else if ("GET".equals(method)) {
            reqData = httpServletRequest.getParameter("data");
        }
        log.info("请求数据：url={}, method={}, reqData: {}", url, method, reqData);
        String newData = null;

        boolean blcCheck = true;
        if ("MTSaas".equals(url.split("/")[0]) || url.startsWith("SYS/") || url.startsWith("sys/")) {
            if("MTSaas".equals(url.split("/")[0])){
                url = "/" + url.substring(url.indexOf("MTSaas/"));
            }
            if(url.startsWith("SYS/")) {
                url = "/" + url.substring(url.indexOf("SYS/"));
            }
            if(url.startsWith("sys/")) {
                url = "/" + url.substring(url.indexOf("sys/"));
            }
            newData = reqData;
            blcCheck = false;
            //liby 2019-08-20 不走加密模式，带项目路径访问
            httpServletResponse.setContentType("application/json; charset=UTF-8");
            ServletContext sc = httpServletRequest.getServletContext();
            RequestDispatcher dispatcher = sc.getRequestDispatcher(url);
            dispatcher.forward(httpServletRequest, httpServletResponse);
            return;
        } else if (url.startsWith("UDI/") || url.startsWith("udi/")) {
            url = "/" + url.substring(url.indexOf("UDI/"));
//            newData = reqData;
//            blcCheck = false;
            httpServletResponse.setContentType("application/json; charset=UTF-8");
            ServletContext sc = httpServletRequest.getServletContext();
            RequestDispatcher dispatcher = sc.getRequestDispatcher(url);
            dispatcher.forward(httpServletRequest, httpServletResponse);
            return;
        } else {
            try {
//            newData = reqData;
                newData = AESTool.decrypt(reqData);
            } catch (Exception e) {
                log.info("解密失败：", e);
            }
        }
        JSONObject json = JSON.parseObject(newData);
        JSONObject jmetdata = json.getJSONObject("metdata");
        MDC.put("staff", jmetdata.getString("user"));
        MDC.put("code", jmetdata.getString("model_code"));
        if (isInclude(url) && blcCheck) {
            /**
             * session 检查
             */
            if (httpServletRequest.getSession() == null || httpServletRequest.getSession().getAttribute(httpServletRequest.getSession().getId() + "stuff") == null) {
                servletRequest.getRequestDispatcher("/ERROR/session").forward(servletRequest, servletResponse);
                return;
            }
            /**
             * 记录操作员功能日志表
             * */
            String s = (String) httpServletRequest.getSession().getAttribute(httpServletRequest.getSession().getId() + "stuff");
//            JSONObject jsonObject = JSON.parseObject(s);
//            StuffPojo stuffPojo = jsonObject.toJavaObject(StuffPojo.class);
//            AiStuffLog aiStuffLog = new AiStuffLog();
//            aiStuffLog.setBranchId(stuffPojo.getBranchId());
//            aiStuffLog.setCustId(stuffPojo.getCustId());
//            aiStuffLog.setStaffLoginId(stuffPojo.getId());
//            aiStuffLog.setFuncCode(jmetdata.getString("func_code"));
//            aiStuffLog.setSysIp(jmetdata.getString("ip_address"));
//            aiStuffLog.setSysOper(jmetdata.getString("user"));
//            aiStuffLog.setSysReqsrc(jmetdata.getString("req_src"));
//            aiStuffLog.setSysIpBelongsto(jmetdata.getString("address"));
//            aiStuffLog.setSysDatetime(new Date());
//            aiStuffLog.setSysId(UUID.randomUUID().toString());
//            try {
//                aiStuffLogDao.insert(aiStuffLog);
//            }catch (Exception e){
//                log.error("插入操作员功能日志表信息出错！" + aiStuffLog.toString());
//                log.error("插入操作员功能日志表信息出错！" , e);
//            }
        }
        /**
         * 记录AI处理日志表
         * */
        AiIntrmgrProcess aiIntrmgrProcess = new AiIntrmgrProcess();
        aiIntrmgrProcess.setFuncCode(url);
        aiIntrmgrProcess.setIntfId(UUID.randomUUID().toString());
        aiIntrmgrProcess.setIntfReqMessage(newData);
        aiIntrmgrProcess.setIntfVersion("1.0");
        aiIntrmgrProcess.setSysReqsrc(jmetdata.getString("req_src"));
        aiIntrmgrProcess.setSysOper(jmetdata.getString("user"));
        aiIntrmgrProcess.setSysIp(jmetdata.getString("ip_address"));
        aiIntrmgrProcess.setSysStart(new Date(System.currentTimeMillis()));
        aiIntrmgrProcess.setFromSysReqsrc("AIWEB");
        aiIntrmgrProcess.setToSysReqsrc("AISERVICE");
        try {
//            aiIntrmgrProcessDao.insert(aiIntrmgrProcess);
        } catch (Exception e) {
            log.error("插入AI处理日志表信息出错！" + aiIntrmgrProcess.toString());
            log.error("插入AI处理日志表信息出错！", e);
        }
        HttpSession session = httpServletRequest.getSession();
        session.setAttribute(session.getId() + "aiIntrmgrProcess", aiIntrmgrProcess.getIntfId());
        ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper(httpServletRequest);
        requestWrapper.addParameter("data", newData);
        filterChain.doFilter(requestWrapper, httpServletResponse);
//        filterChain.doFilter(contentCachingRequestWrapper, servletResponse);
    }

    @Override
    public void destroy() {

    }

    /**
     * 是否需要过滤
     *
     * @param url
     * @return
     */
    private boolean isInclude(String url) {
        for (String path : paths) {
            if (path.equals(url)) {
                return false;
            }
        }
        return true;
    }

    private void writeToLog(String url, String method, String sbdata) {
        if ("POST".equals(method) || "PUT".equals(method) || "PATCH".equals(method) || "DELETE".equals(method)) {

            log.info("请求数据：url={}, method={}, reqData: {}", url, method, sbdata);

            RequestPojo requestPojo = ParamUtil.doChange();

            JSONObject jsonObject = JSONObject.parseObject(sbdata);
            JSONObject jmetdata = jsonObject.getJSONObject("metdata");
            TIntfLog intfProcess = new TIntfLog();
            intfProcess.setRequestUrl(url);
            intfProcess.setInterfaceType(method);
            intfProcess.setUniqueKey(UUID.randomUUID().toString());
            intfProcess.setRequestMsg(jsonObject.toString());
            if (Objects.nonNull(jmetdata)) {
                intfProcess.setFromSys(jmetdata.getString("req_src"));
            }
            intfProcess.setCompanyId(Long.valueOf(requestPojo.getCustId()));
            intfProcess.setCreateBy(requestPojo.getUserName());
            intfProcess.setCreateTime(new Date());
            intfProcess.setIsEnabled(0);
            intfProcess.setTargSys("MTSaas");
            try {
                tIntfLogDao.insert(intfProcess);
            } catch (Exception e) {
                log.error("插入日志表信息出错！" + intfProcess.toString());
                log.error("插入日志表信息出错！", e);
            }
        }
    }

    /**
     * 深拷贝HttpServletRequest对象，该方法异常不可用
     *
     * @param original
     * @return
     */
    public HttpServletRequest deepCopy(HttpServletRequest original) {
        try {
            // 将请求对象序列化成字节数组
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(byteOut);
            out.writeObject(original);
            out.flush();
            byte[] requestBytes = byteOut.toByteArray();

            // 将字节数组反序列化成新的请求对象
            ByteArrayInputStream byteIn = new ByteArrayInputStream(requestBytes);
            ObjectInputStream in = new ObjectInputStream(byteIn);
            return (HttpServletRequest) in.readObject();

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}
